package utils;

import java.io.FileNotFoundException;
import java.io.PrintStream;
import java.util.HashMap;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import org.dom4j.tree.DefaultElement;

/**
 * manage the config.xml file, get or set system information while application
 * is running
 * 
 * @author huangcd
 * 
 */
public class Configuration
{
    public static String                   RootPath;
    public static String                   WordListFile;
    public static String                   IDListFile;
    public static String                   DataSetPath;
    public static String                   DatabasePath;
    public static String                   ResourcePath;
    public static boolean                 cacheXML;
    private static final String            CONFIG_XML = "config.xml";
    private static final String            DATA       = "data";
    private static final String            CLU        = "clustering";
    private static final String            CLA        = "classification";
    private static final String            SIM        = "similarity";
    private static final String            RET        = "retreival";
    private static Document                config;
    private static HashMap<String, String> cache;
    private static boolean                 changed;

    /**
     * Initialization and add a shutdown hook to the application
     */
    static
    {
        changed = false;
        cache = new HashMap<String, String>();
        try
        {
            SAXReader reader = new SAXReader();
            config = reader.read(CONFIG_XML);
        }
        catch (final DocumentException e)
        {
            e.printStackTrace();
        }
        // save the document to file while application close
        Runtime.getRuntime().addShutdownHook(new Thread()
        {
            @Override
            public void run()
            {
                if (!Configuration.changed)
                    return;
                try
                {
                    PrintStream out = new PrintStream(CONFIG_XML);
                    out.print(config.asXML());
                }
                catch (FileNotFoundException e)
                {
                    e.printStackTrace();
                }
            }
        });
        RootPath = getAttribute(DATA, "root_path");
        WordListFile = RootPath + getAttribute(DATA, "word_list_path");
        IDListFile = RootPath + getAttribute(DATA, "id_list_path");
        DataSetPath = RootPath + getAttribute(DATA, "data_set_Path");
        DatabasePath = RootPath + getAttribute(DATA, "database_path");
        ResourcePath = RootPath + getAttribute(DATA, "resource_path");
        cacheXML = getAttribute(DATA, "cacheXML").toLowerCase().equals("true");
    }

    public static class SIMILARITY
    {
        public static String feature_template;
        public static String tempalte_database;
        public static String struct_similarity_database;
        public static String feature_struct_similarity;

        static
        {
            feature_template = getAttribute(SIM, "feature_template");
            tempalte_database = getAttribute(SIM, "tempalte_database");
            struct_similarity_database = getAttribute(SIM,
                    "struct_similarity_database");
            feature_struct_similarity = getAttribute(SIM,
                    "feature_struct_similarity");
        }
    }

    public static class CLASSIFICATION
    {
        public static String classification_src_path;

        static
        {
            classification_src_path = RootPath + "/classification/src/";
        }
    }

    public static class RETRIVAL
    {
        public static String FilePath;
        static
        {
            FilePath = RootPath + getAttribute(RET, "file_path");
        }
    }

    public static class CLUSTERING
    {
        public static String MaxClusterTimes;
        public static String ClusterCount;
        static
        {
            MaxClusterTimes = getAttribute(CLU, "max_cluster_times");
            ClusterCount = getAttribute(CLU, "cluter_count");
        }
    }

    /**
     * set an attribute
     * 
     * @param type
     *            type that the attribute should belong to, default types
     *            contain: data, clustering, classification, query. different
     *            attributes should save in different type
     * @param attribute
     *            attribute name
     * @param value
     *            attribute value
     * @return true if the set action succeed, false if failed.
     */
    public static boolean setAttribute(String type, String attribute,
            String value)
    {
        changed = true;
        if (config == null) { return false; }
        String key = type + "$" + attribute;
        cache.put(key, value);
        Node node = config.selectSingleNode("/config/" + type);
        if (node == null)
        {
            Element root = config.getRootElement();
            Element newElem = new DefaultElement(type);
            newElem.addAttribute(attribute, value);
            root.add(newElem);
        }
        else
        {
            Element elem = (Element) config.selectSingleNode("/config/" + type);
            elem.addAttribute(attribute, value);
        }
        return true;
    }

    /**
     * get an attribute value by the type and the attribute name
     * 
     * @param type
     *            type that the attribute should belong to, default types
     *            contain: data, clustering, classification, query. different
     *            attributes should save in different type
     * @param attribute
     *            attribute name
     * @return attribute value
     */
    public static String getAttribute(String type, String attribute)
    {
        if (config == null) { return null; }
        String key = type + "$" + attribute;
        if (cache.containsKey(key)) { return cache.get(key); }
        Node node = config.selectSingleNode("/config/" + type);
        if (node == null) { return null; }
        Element elem = (Element) node;
        String value = elem.attributeValue(attribute);
        cache.put(key, value);
        return value;
    }

    /**
     * demo of this class
     * 
     * @param args
     */
    public static void main(String[] args)
    {
        // get an attribute
        System.out.println(getAttribute(DATA, "root_path"));
        // set an attribute
        // setAttribute("data", "db_suffix", "yap");
        // setAttribute("clustering", "cluter_count", "21");
        // setAttribute(SIMILARITY, "word_list_path", "./wl.txt");
        // setAttribute(SIMILARITY, "id_list_path", "./id.txt");
    }
}
